
/**
 * Promise
 * @param {*} exextor 
 * @value  promise 成功后的值
 * @reason promise失败的原因
 * @status promise的值 初始为pending
 * @resolveCallback promise 成功后执行的回调函数队列
 * @rejectCallback promise 失败后执行的回调函数队列
 * 
 * status 仅能从 pending ==> fulfilled or pending ==> rejected 
 * promise 的实例拥有then方法
 * 
 */

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'


type PromiseStatus = 'pending' | 'fulfilled' | 'rejected';



type TExector = (resolve: ((params?: any) => any), reject: ((params?: any) => any)) => any



class MyPromise {
    private status: PromiseStatus;
    private value: any;
    private reason: any;
    private resolveCallback: Array<(params?: any) => any>;
    private rejectCallback: Array<(params?: any) => any>;
    constructor(exector: TExector) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.resolveCallback = []
        this.rejectCallback = []
        try {
            exector(this.resolve.bind(this), this.reject.bind(this))
        } catch (e) {
            this.reject(e)
        }
    }
    private resolve(value: any) {
        if (this.status === PENDING) {
            this.status = FULFILLED;
            this.value = value;
            this.resolveCallback.forEach((cb) => {
                cb && cb(value)
            })
        }
    }
    private reject(reason: any) {
        if (this.status === PENDING) {
            this.status = FULFILLED;
            this.reason = reason;
            this.rejectCallback.forEach((cb) => {
                cb && cb(reason)
            })
        }
    }
    then(onFulfilled?: any, onRejected?: any) {
        const fulfillCallback = typeof onFulfilled === 'function' ? onFulfilled : (value: any) => value
        const rejectCallback = typeof onRejected === 'function' ? onRejected : (reason: any) => { throw reason }

        let promise: MyPromise | undefined;
        if (this.status === FULFILLED) {
            return promise = new MyPromise((resolve, reject) => {
                try {
                    const x = fulfillCallback(this.value)

                    if (x instanceof MyPromise) {
                        x.then(resolve, reject)
                    }
                    resolve(x)
                } catch (e) {
                    reject(e)
                }
            })

        } else if (this.status === REJECTED) {
            return promise = new MyPromise((resolve, reject) => {

                try {
                    const x = rejectCallback(this.reason)
                    if (x instanceof MyPromise) {
                        x.then(resolve, reject)
                    }
                    reject(x)
                } catch (e) {
                    reject(e)
                }
            })

        } else {
            return promise = new MyPromise((resolve, reject) => {
                this.resolveCallback.push((value: any) => {
                    try {
                        const x = fulfillCallback(value)

                        if (x instanceof MyPromise) {
                            x.then(resolve, reject)
                        }
                        resolve(x)
                    } catch (e) {
                        reject(e)
                    }
                })
                this.rejectCallback.push((reason: any) => {
                    try {
                        const x = rejectCallback(reason)

                        if (x instanceof MyPromise) {
                            x.then(resolve, reject)
                        }
                        reject(x)
                    } catch (e) {
                        reject(e)
                    }
                })


            })
        }

    }
    catch(onRejected: any) {
        this.then(null, onRejected)
    }
}
console.log( 1 );

const p1 = new MyPromise((resolve,reject)=>{
    setTimeout(()=>{
        reject(1)
    },1000)
})

 const p2 = new MyPromise((resolve, reject) => {
    console.log( 2 );
    setTimeout(()=>{
        resolve(p1)
    })
}).then((res: any) => {
  
    console.log( res );
    

})
console.log(p2 );